#include "redis.hpp"      // redis数据管理客户端封装
#include "etcd.hpp"     // 服务注册模块封装
#include "channel.hpp"  // 信道管理模块封装

#include "connection.hpp"

#include "user.pb.h"  // protobuf框架代码
#include "base.pb.h"  // protobuf框架代码
#include "file.pb.h"  // protobuf框架代码
#include "friend.pb.h"  // protobuf框架代码
#include "gateway.pb.h"  // protobuf框架代码
#include "message.pb.h"  // protobuf框架代码
#include "speech.pb.h"  // protobuf框架代码
#include "transmit.pb.h"  // protobuf框架代码
#include "notify.pb.h"

#include "httplib.h"



namespace zzy_mims
{
    #define GET_PHONE_VERIFY_CODE   "/service/user/get_phone_verify_code"
    #define USERNAME_REGISTER       "/service/user/username_register"
    #define USERNAME_LOGIN          "/service/user/username_login"
    #define PHONE_REGISTER          "/service/user/phone_register"
    #define PHONE_LOGIN             "/service/user/phone_login"
    #define GET_USERINFO            "/service/user/get_user_info"
    #define SET_USER_AVATAR         "/service/user/set_avatar"
    #define SET_USER_NICKNAME       "/service/user/set_nickname"
    #define SET_USER_DESC           "/service/user/set_description"
    #define SET_USER_PHONE          "/service/user/set_phone"
    #define FRIEND_GET_LIST         "/service/friend/get_friend_list"
    #define FRIEND_APPLY            "/service/friend/add_friend_apply"
    #define FRIEND_APPLY_PROCESS    "/service/friend/add_friend_process"
    #define FRIEND_REMOVE           "/service/friend/remove_friend"
    #define FRIEND_SEARCH           "/service/friend/search_friend"
    #define FRIEND_GET_PENDING_EV   "/service/friend/get_pending_friend_events"
    #define CSS_GET_LIST            "/service/friend/get_chat_session_list"
    #define CSS_CREATE              "/service/friend/create_chat_session"
    #define CSS_GET_MEMBER          "/service/friend/get_chat_session_member"
    #define MSG_GET_RANGE           "/service/message_storage/get_history"
    #define MSG_GET_RECENT          "/service/message_storage/get_recent"
    #define MSG_KEY_SEARCH          "/service/message_storage/search_history"
    #define NEW_MESSAGE             "/service/message_transmit/new_message"
    #define FILE_GET_SINGLE         "/service/file/get_single_file"
    #define FILE_GET_MULTI          "/service/file/get_multi_file"
    #define FILE_PUT_SINGLE         "/service/file/put_single_file"
    #define FILE_PUT_MULTI          "/service/file/put_multi_file"
    #define SPEECH_RECOGNITION      "/service/speech/recognition"


    class GatewayServer
    {
    public:
        using ptr = shared_ptr<GatewayServer>;
        GatewayServer(int websocket_port,int http_port,
        const std::shared_ptr<sw::redis::Redis>& redis_client,
        const ServChanManager::ptr& channels,
        const Discovery::ptr& service_discoverer,
        const std::string user_service_name,
        const std::string file_service_name,
        const std::string speech_service_name,
        const std::string message_service_name,
        const std::string transmit_service_name,
        const std::string friend_service_name)
        :_redis_session(make_shared<Session>(redis_client)),
        _redis_status(make_shared<Status>(redis_client)),
        _mm_channels(channels),
        _service_discoverer(service_discoverer),
        _user_service_name(user_service_name),
        _file_service_name(file_service_name),
        _speech_service_name(speech_service_name),
        _message_service_name(message_service_name),
        _transmit_service_name(transmit_service_name),
        _friend_service_name(friend_service_name),
        _conn(std::make_shared<Connection>())
        {
            _ws_server.set_access_channels(websocketpp::log::alevel::none);
            _ws_server.init_asio();
            _ws_server.set_open_handler(std::bind(&GatewayServer::onOpen,this,std::placeholders::_1));
            _ws_server.set_close_handler(std::bind(&GatewayServer::onClose,this,std::placeholders::_1));
            _ws_server.set_message_handler(std::bind(&GatewayServer::onMessage,this,std::placeholders::_1,std::placeholders::_2));
            _ws_server.set_reuse_addr(true);
            _ws_server.listen(websocket_port);
            _ws_server.start_accept();
            _http_server.Post(GET_PHONE_VERIFY_CODE  , (httplib::Server::Handler)std::bind(&GatewayServer::GetPhoneVerifyCode         , this, std::placeholders::_1, std::placeholders::_2));
            _http_server.Post(USERNAME_REGISTER      , (httplib::Server::Handler)std::bind(&GatewayServer::UserRegister               , this, std::placeholders::_1, std::placeholders::_2));
            _http_server.Post(USERNAME_LOGIN         , (httplib::Server::Handler)std::bind(&GatewayServer::UserLogin                  , this, std::placeholders::_1, std::placeholders::_2));
            _http_server.Post(PHONE_REGISTER         , (httplib::Server::Handler)std::bind(&GatewayServer::PhoneRegister              , this, std::placeholders::_1, std::placeholders::_2));
            _http_server.Post(PHONE_LOGIN            , (httplib::Server::Handler)std::bind(&GatewayServer::PhoneLogin                 , this, std::placeholders::_1, std::placeholders::_2));
            _http_server.Post(GET_USERINFO           , (httplib::Server::Handler)std::bind(&GatewayServer::GetUserInfo                , this, std::placeholders::_1, std::placeholders::_2));
            _http_server.Post(SET_USER_AVATAR        , (httplib::Server::Handler)std::bind(&GatewayServer::SetUserAvatar              , this, std::placeholders::_1, std::placeholders::_2));
            _http_server.Post(SET_USER_NICKNAME      , (httplib::Server::Handler)std::bind(&GatewayServer::SetUserNickname            , this, std::placeholders::_1, std::placeholders::_2));
            _http_server.Post(SET_USER_DESC          , (httplib::Server::Handler)std::bind(&GatewayServer::SetUserDescription         , this, std::placeholders::_1, std::placeholders::_2));
            _http_server.Post(SET_USER_PHONE         , (httplib::Server::Handler)std::bind(&GatewayServer::SetUserPhoneNumber         , this, std::placeholders::_1, std::placeholders::_2));
            _http_server.Post(FRIEND_GET_LIST        , (httplib::Server::Handler)std::bind(&GatewayServer::GetFriendList              , this, std::placeholders::_1, std::placeholders::_2));
            _http_server.Post(FRIEND_APPLY           , (httplib::Server::Handler)std::bind(&GatewayServer::FriendAdd                  , this, std::placeholders::_1, std::placeholders::_2));
            _http_server.Post(FRIEND_APPLY_PROCESS   , (httplib::Server::Handler)std::bind(&GatewayServer::FriendAddProcess           , this, std::placeholders::_1, std::placeholders::_2));
            _http_server.Post(FRIEND_REMOVE          , (httplib::Server::Handler)std::bind(&GatewayServer::FriendRemove               , this, std::placeholders::_1, std::placeholders::_2));
            _http_server.Post(FRIEND_SEARCH          , (httplib::Server::Handler)std::bind(&GatewayServer::FriendSearch               , this, std::placeholders::_1, std::placeholders::_2));
            _http_server.Post(FRIEND_GET_PENDING_EV  , (httplib::Server::Handler)std::bind(&GatewayServer::GetPendingFriendEventList  , this, std::placeholders::_1, std::placeholders::_2));
            _http_server.Post(CSS_GET_LIST           , (httplib::Server::Handler)std::bind(&GatewayServer::GetChatSessionList         , this, std::placeholders::_1, std::placeholders::_2));
            _http_server.Post(CSS_CREATE             , (httplib::Server::Handler)std::bind(&GatewayServer::ChatSessionCreate          , this, std::placeholders::_1, std::placeholders::_2));
            _http_server.Post(CSS_GET_MEMBER         , (httplib::Server::Handler)std::bind(&GatewayServer::GetChatSessionMember       , this, std::placeholders::_1, std::placeholders::_2));
            _http_server.Post(MSG_GET_RANGE          , (httplib::Server::Handler)std::bind(&GatewayServer::GetHistoryMsg              , this, std::placeholders::_1, std::placeholders::_2));
            _http_server.Post(MSG_GET_RECENT         , (httplib::Server::Handler)std::bind(&GatewayServer::GetRecentMsg               , this, std::placeholders::_1, std::placeholders::_2));
            _http_server.Post(MSG_KEY_SEARCH         , (httplib::Server::Handler)std::bind(&GatewayServer::MsgSearch                  , this, std::placeholders::_1, std::placeholders::_2));
            _http_server.Post(NEW_MESSAGE            , (httplib::Server::Handler)std::bind(&GatewayServer::NewMessage                 , this, std::placeholders::_1, std::placeholders::_2));
            _http_server.Post(FILE_GET_SINGLE        , (httplib::Server::Handler)std::bind(&GatewayServer::GetSingleFile              , this, std::placeholders::_1, std::placeholders::_2));
            _http_server.Post(FILE_GET_MULTI         , (httplib::Server::Handler)std::bind(&GatewayServer::GetMultiFile               , this, std::placeholders::_1, std::placeholders::_2));
            _http_server.Post(FILE_PUT_SINGLE        , (httplib::Server::Handler)std::bind(&GatewayServer::PutSingleFile              , this, std::placeholders::_1, std::placeholders::_2));
            _http_server.Post(FILE_PUT_MULTI         , (httplib::Server::Handler)std::bind(&GatewayServer::PutMultiFile               , this, std::placeholders::_1, std::placeholders::_2));
            _http_server.Post(SPEECH_RECOGNITION     , (httplib::Server::Handler)std::bind(&GatewayServer::SpeechRecognition          , this, std::placeholders::_1, std::placeholders::_2));
            _http_thread = std::thread([this, http_port]()
            {
                _http_server.listen("0.0.0.0",http_port);
            });
            _http_thread.detach();
            
        };
        void start()
        {
            _ws_server.run();
        }
    private:
        void onOpen(websocketpp::connection_hdl hdl)
        {
            LOG_DEBUG("websocket长连接建立成功{}",(size_t)_ws_server.get_con_from_hdl(hdl).get());
        };
        void onClose(websocketpp::connection_hdl hdl)
        {
            //查找对应连接的客户端，根据客户端的消息清除对应缓存
            auto conn = _ws_server.get_con_from_hdl(hdl);
            std::string uid,sid;
            bool ret = _conn->client(conn,uid,sid);
            if(!ret)
            {
                LOG_WARN("未找到长连接对应的客户端\n");
                return;
            }
            _redis_session->remove(sid);
            _redis_status->remove(uid);
            _conn->remove(conn);
            LOG_DEBUG("删除长连接{}:{}-{}，清理缓存\n",(size_t)conn.get(),uid,sid);
            
        };
        void KeepAlive(server_t::connection_ptr conn)
        {
            //判断是否主动关闭连接，或出现其他异常
            //没有就ping一下，保持连接不断开

            //如果这个长连接已经处于保活状态了，就直接退出
            if(_judge_alive[(size_t)conn.get()])
            return;
            _judge_alive[(size_t)conn.get()] = 1;
            if(!conn||conn->get_state()!=websocketpp::session::state::value::open)
            {
                _judge_alive[(size_t)conn.get()] = 0;
                LOG_DEBUG("长连接状态异常,结束保活\n");
                return;
            }
            conn->ping("");
            _ws_server.set_timer(60000,std::bind(&GatewayServer::KeepAlive,this,conn));
        };
        void onMessage(websocketpp::connection_hdl hdl,server_t::message_ptr msg)
        {
            auto conn = _ws_server.get_con_from_hdl(hdl);
            ClientAuthenticationReq req;
            bool ret = req.ParseFromString(msg->get_payload());

            if(!ret)
            {
                LOG_ERROR("接受到的消息正文反序列化失败!\n");
                _ws_server.close(hdl,websocketpp::close::status::unsupported_data,"正文序列化失败");
                return;
            }
            std::string sid = req.session_id();
            auto uid = _redis_session->uid(sid);
            if(!uid)
            {
                LOG_ERROR("接受到的消息的sid:{}不能找到对应的用户!\n",sid);
                _ws_server.close(hdl,websocketpp::close::status::unsupported_data,"接受到的消息的sid不能找到对应的用户");
                return;
            }
            //发送的消息合法，保证对应的长连接被管理
            _conn->insert(conn,*uid,sid);
            LOG_DEBUG("长连接:{}:{}-{}被管理",(size_t)conn.get(),*uid,sid);
            KeepAlive(conn);
        };
        void GetPhoneVerifyCode(const httplib::Request &request, httplib::Response &response) 
        {
            //1.取出http正文，将正文反序列化
            PhoneVerifyCodeReq req;
            PhoneVerifyCodeRsp rsp;
            auto err_handler = [&req,&rsp,&response](const std::string& errmsg)
            {
                rsp.set_success(false);
                rsp.set_errmsg(errmsg);
                response.set_content(rsp.SerializeAsString(),"application/x-protobuf");
                return;
            };
            bool ret = req.ParseFromString(request.body);
            if(!ret)
            {
                LOG_ERROR("获取短信验证码请求反序列化失败\n");
                return err_handler("获取短信验证码请求反序列化失败");
            }
            //2.将请求转发到对应的子服务进行处理
            auto channel = _mm_channels->choose(_user_service_name);
            if(!channel)
            {
                LOG_ERROR("{}:未找到可提供短信验证的用户子服务节点\n",req.request_id());
                return err_handler("未找到可提供短信验证的用户子服务节点");
            }
            zzy_mims::UserService_Stub stub(channel.get());
            brpc::Controller cntl;
            stub.GetPhoneVerifyCode(&cntl,&req,&rsp,nullptr);
            if(cntl.Failed())
            {
                LOG_ERROR("{}:用户子服务:短信验证调用失败\n",req.request_id());
                return err_handler("用户子服务:短信验证调用失败");
            }
            //执行错误也是一种正确的响应
            // if(!rsp.success())
            // {
            //     LOG_ERROR("{}:用户子服务:短信验证处理失败\n",req.request_id());
            //     return err_handler("用户子服务:短信验证处理失败");
            // }
            //3.得到正确的对应的子服务的响应后，将响应内容进行序列化作为http响应正文
            response.set_content(rsp.SerializeAsString(),"application/x-protobuf");   
        }
        void UserRegister(const httplib::Request &request, httplib::Response &response) 
        {
            //1.取出http正文，将正文反序列化
            UserRegisterReq req;
            UserRegisterRsp rsp;
            auto err_handler = [&req,&rsp,&response](const std::string& errmsg)
            {
                rsp.set_success(false);
                rsp.set_errmsg(errmsg);
                response.set_content(rsp.SerializeAsString(),"application/x-protobuf");
                return;
            };
            bool ret = req.ParseFromString(request.body);
            if(!ret)
            {
                LOG_ERROR("用户注册请求反序列化失败\n");
                return err_handler("用户注册请求反序列化失败");
            }
            //2.将请求转发到对应的子服务进行处理
            auto channel = _mm_channels->choose(_user_service_name);
            if(!channel)
            {
                LOG_ERROR("{}:未找到可提供用户注册的用户子服务节点\n",req.request_id());
                return err_handler("未找到可提供用户注册的用户子服务节点");
            }
            zzy_mims::UserService_Stub stub(channel.get());
            brpc::Controller cntl;
            stub.UserRegister(&cntl,&req,&rsp,nullptr);
            if(cntl.Failed())
            {
                LOG_ERROR("{}:用户子服务:用户注册调用失败\n",req.request_id());
                return err_handler("用户子服务:用户注册调用失败");
            }
            //执行错误也是一种正确的响应
            // if(!rsp.success())
            // {
            //     LOG_ERROR("{}:用户子服务:用户注册处理失败\n",req.request_id());
            //     return err_handler("用户子服务:用户注册处理失败");
            // }
            //3.得到正确的对应的子服务的响应后，将响应内容进行序列化作为http响应正文
            response.set_content(rsp.SerializeAsString(),"application/x-protobuf");   
        }

        void UserLogin(const httplib::Request &request, httplib::Response &response)
        {
            //1.取出http正文，将正文反序列化
            UserLoginReq req;
            UserLoginRsp rsp;
            auto err_handler = [&req,&rsp,&response](const std::string& errmsg)
            {
                rsp.set_success(false);
                rsp.set_errmsg(errmsg);
                response.set_content(rsp.SerializeAsString(),"application/x-protobuf");
                return;
            };
            bool ret = req.ParseFromString(request.body);
            if(!ret)
            {
                LOG_ERROR("用户登录请求反序列化失败\n");
                return err_handler("用户登录请求反序列化失败");
            }
            //2.将请求转发到对应的子服务进行处理
            auto channel = _mm_channels->choose(_user_service_name);
            if(!channel)
            {
                LOG_ERROR("{}:未找到可提供用户登录的用户子服务节点\n",req.request_id());
                return err_handler("未找到可提供用户登录的用户子服务节点");
            }
            zzy_mims::UserService_Stub stub(channel.get());
            brpc::Controller cntl;
            stub.UserLogin(&cntl,&req,&rsp,nullptr);
            if(cntl.Failed())
            {
                LOG_ERROR("{}:用户子服务:用户登录调用失败\n",req.request_id());
                return err_handler("用户子服务:用户登录调用失败");
            }
            //执行错误也是一种正确的响应
            // if(!rsp.success())
            // {
            //     LOG_ERROR("{}:用户子服务:用户登录处理失败\n",req.request_id());
            //     return err_handler("用户子服务:用户登录处理失败");
            // }
            //3.得到正确的对应的子服务的响应后，将响应内容进行序列化作为http响应正文
            response.set_content(rsp.SerializeAsString(),"application/x-protobuf");   

        }
        void PhoneRegister(const httplib::Request &request, httplib::Response &response)
        {
            //1.取出http正文，将正文反序列化
            PhoneRegisterReq req;
            PhoneRegisterRsp rsp;
            auto err_handler = [&req,&rsp,&response](const std::string& errmsg)
            {
                rsp.set_success(false);
                rsp.set_errmsg(errmsg);
                response.set_content(rsp.SerializeAsString(),"application/x-protobuf");
                return;
            };
            bool ret = req.ParseFromString(request.body);
            if(!ret)
            {
                LOG_ERROR("电话注册请求反序列化失败\n");
                return err_handler("电话注册请求反序列化失败");
            }
            //2.将请求转发到对应的子服务进行处理
            auto channel = _mm_channels->choose(_user_service_name);
            if(!channel)
            {
                LOG_ERROR("{}:未找到可提供电话注册的用户子服务节点\n",req.request_id());
                return err_handler("未找到可提供电话注册的用户子服务节点");
            }
            zzy_mims::UserService_Stub stub(channel.get());
            brpc::Controller cntl;
            stub.PhoneRegister(&cntl,&req,&rsp,nullptr);
            if(cntl.Failed())
            {
                LOG_ERROR("{}:用户子服务:电话注册调用失败\n",req.request_id());
                return err_handler("用户子服务:电话注册调用失败");
            }
            //执行错误也是一种正确的响应
            // if(!rsp.success())
            // {
            //     LOG_ERROR("{}:用户子服务:电话注册处理失败\n",req.request_id());
            //     return err_handler("用户子服务:电话注册处理失败");
            // }
            //3.得到正确的对应的子服务的响应后，将响应内容进行序列化作为http响应正文
            response.set_content(rsp.SerializeAsString(),"application/x-protobuf");   

        }
        void PhoneLogin(const httplib::Request &request, httplib::Response &response) 
        {
            //1.取出http正文，将正文反序列化
            PhoneLoginReq req;
            PhoneLoginRsp rsp;
            auto err_handler = [&req,&rsp,&response](const std::string& errmsg)
            {
                rsp.set_success(false);
                rsp.set_errmsg(errmsg);
                response.set_content(rsp.SerializeAsString(),"application/x-protobuf");
                return;
            };
            bool ret = req.ParseFromString(request.body);
            if(!ret)
            {
                LOG_ERROR("电话登录请求反序列化失败\n");
                return err_handler("电话登录请求反序列化失败");
            }
            //2.将请求转发到对应的子服务进行处理
            auto channel = _mm_channels->choose(_user_service_name);
            if(!channel)
            {
                LOG_ERROR("{}:未找到可提供电话登录的用户子服务节点\n",req.request_id());
                return err_handler("未找到可提供电话登录的用户子服务节点");
            }
            zzy_mims::UserService_Stub stub(channel.get());
            brpc::Controller cntl;
            stub.PhoneLogin(&cntl,&req,&rsp,nullptr);
            if(cntl.Failed())
            {
                LOG_ERROR("{}:用户子服务:电话登录调用失败\n",req.request_id());
                return err_handler("用户子服务:电话登录调用失败");
            }
            //执行错误也是一种正确的响应
            // if(!rsp.success())
            // {
            //     LOG_ERROR("{}:用户子服务:电话登录处理失败\n",req.request_id());
            //     return err_handler("用户子服务:电话登录处理失败");
            // }
            //3.得到正确的对应的子服务的响应后，将响应内容进行序列化作为http响应正文
            response.set_content(rsp.SerializeAsString(),"application/x-protobuf");   

        }
        void GetUserInfo(const httplib::Request &request, httplib::Response &response) 
        {
            //1.取出http正文，将正文反序列化
            GetUserInfoReq req;
            GetUserInfoRsp rsp;
            auto err_handler = [&req,&rsp,&response](const std::string& errmsg)
            {
                rsp.set_success(false);
                rsp.set_errmsg(errmsg);
                response.set_content(rsp.SerializeAsString(),"application/x-protobuf");
                return;
            };
            bool ret = req.ParseFromString(request.body);
            if(!ret)
            {
                LOG_ERROR("获取用户信息请求反序列化失败\n");
                return err_handler("获取用户信息请求反序列化失败");
            }
            //2.进行客户端身份的识别与鉴权
            std::string sid = req.session_id();
            auto uid = _redis_session->uid(sid);
            if(!uid)
            {
                LOG_ERROR("获取登录会话:{}关联的用户ID失败\n",sid);
                return err_handler("获取登录会话关联的用户ID失败");
            }
            req.set_user_id(*uid);
            //3.将请求转发到对应的子服务进行处理
            auto channel = _mm_channels->choose(_user_service_name);
            if(!channel)
            {
                LOG_ERROR("{}:未找到可提供获取用户信息的用户子服务节点\n",req.request_id());
                return err_handler("未找到可提供获取用户信息的用户子服务节点");
            }
            zzy_mims::UserService_Stub stub(channel.get());
            brpc::Controller cntl;
            stub.GetUserInfo(&cntl,&req,&rsp,nullptr);
            if(cntl.Failed())
            {
                LOG_ERROR("{}:用户子服务:获取用户信息调用失败\n",req.request_id());
                return err_handler("用户子服务:获取用户信息调用失败");
            }
            //执行错误也是一种正确的响应
            // if(!rsp.success())
            // {
            //     LOG_ERROR("{}:用户子服务:获取用户信息处理失败\n",req.request_id());
            //     return err_handler("用户子服务:获取用户信息处理失败");
            // }
            //4.得到正确的对应的子服务的响应后，将响应内容进行序列化作为http响应正文
            response.set_content(rsp.SerializeAsString(),"application/x-protobuf");
        }
        void SetUserAvatar(const httplib::Request &request, httplib::Response &response)
        {
            //1.取出http正文，将正文反序列化
            SetUserAvatarReq req;
            SetUserAvatarRsp rsp;
            auto err_handler = [&req,&rsp,&response](const std::string& errmsg)
            {
                rsp.set_success(false);
                rsp.set_errmsg(errmsg);
                response.set_content(rsp.SerializeAsString(),"application/x-protobuf");
                return;
            };
            bool ret = req.ParseFromString(request.body);
            if(!ret)
            {
                LOG_ERROR("获取设置头像请求反序列化失败\n");
                return err_handler("获取设置头像请求反序列化失败");
            }
            //2.进行客户端身份的识别与鉴权
            std::string sid = req.session_id();
            auto uid = _redis_session->uid(sid);
            if(!uid)
            {
                LOG_ERROR("获取登录会话:{}关联的用户ID失败\n",sid);
                return err_handler("获取登录会话关联的用户ID失败");
            }
            req.set_user_id(*uid);
            //3.将请求转发到对应的子服务进行处理
            auto channel = _mm_channels->choose(_user_service_name);
            if(!channel)
            {
                LOG_ERROR("{}:未找到可提供获取设置头像的用户子服务节点\n",req.request_id());
                return err_handler("未找到可提供获取设置头像的用户子服务节点");
            }
            zzy_mims::UserService_Stub stub(channel.get());
            brpc::Controller cntl;
            stub.SetUserAvatar(&cntl,&req,&rsp,nullptr);
            if(cntl.Failed())
            {
                LOG_ERROR("{}:用户子服务:获取设置头像调用失败\n",req.request_id());
                return err_handler("用户子服务:获取设置头像调用失败");
            }
            //执行错误也是一种正确的响应
            // if(!rsp.success())
            // {
            //     LOG_ERROR("{}:用户子服务:获取设置头像处理失败\n",req.request_id());
            //     return err_handler("用户子服务:获取设置头像处理失败");
            // }
            //4.得到正确的对应的子服务的响应后，将响应内容进行序列化作为http响应正文
            response.set_content(rsp.SerializeAsString(),"application/x-protobuf");

        }
        void SetUserNickname(const httplib::Request &request, httplib::Response &response) 
        {
            //1.取出http正文，将正文反序列化
            SetUserNicknameReq req;
            SetUserNicknameRsp rsp;
            auto err_handler = [&req,&rsp,&response](const std::string& errmsg)
            {
                rsp.set_success(false);
                rsp.set_errmsg(errmsg);
                response.set_content(rsp.SerializeAsString(),"application/x-protobuf");
                return;
            };
            bool ret = req.ParseFromString(request.body);
            if(!ret)
            {
                LOG_ERROR("获取设置昵称请求反序列化失败\n");
                return err_handler("获取设置昵称请求反序列化失败");
            }
            //2.进行客户端身份的识别与鉴权
            std::string sid = req.session_id();
            auto uid =  _redis_session->uid(sid);
            if(!uid)
            {
                LOG_ERROR("获取登录会话:{}关联的用户ID失败\n",sid);
                return err_handler("获取登录会话关联的用户ID失败");
            }
            req.set_user_id(*uid);
            //3.将请求转发到对应的子服务进行处理
            auto channel = _mm_channels->choose(_user_service_name);
            if(!channel)
            {
                LOG_ERROR("{}:未找到可提供获取设置昵称的用户子服务节点\n",req.request_id());
                return err_handler("未找到可提供获取设置昵称的用户子服务节点");
            }
            zzy_mims::UserService_Stub stub(channel.get());
            brpc::Controller cntl;
            stub.SetUserNickname(&cntl,&req,&rsp,nullptr);
            if(cntl.Failed())
            {
                LOG_ERROR("{}:用户子服务:获取设置昵称调用失败\n",req.request_id());
                return err_handler("用户子服务:获取设置昵称调用失败");
            }
            //执行错误也是一种正确的响应
            // if(!rsp.success())
            // {
            //     LOG_ERROR("{}:用户子服务:获取设置昵称处理失败\n",req.request_id());
            //     return err_handler("用户子服务:获取设置昵称处理失败");
            // }
            //4.得到正确的对应的子服务的响应后，将响应内容进行序列化作为http响应正文
            response.set_content(rsp.SerializeAsString(),"application/x-protobuf");

        }
        void SetUserDescription(const httplib::Request &request, httplib::Response &response)
        {
            //1.取出http正文，将正文反序列化
            SetUserDescriptionReq req;
            SetUserDescriptionRsp rsp;
            auto err_handler = [&req,&rsp,&response](const std::string& errmsg)
            {
                rsp.set_success(false);
                rsp.set_errmsg(errmsg);
                response.set_content(rsp.SerializeAsString(),"application/x-protobuf");
                return;
            };
            bool ret = req.ParseFromString(request.body);
            if(!ret)
            {
                LOG_ERROR("获取设置签名请求反序列化失败\n");
                return err_handler("获取设置签名请求反序列化失败");
            }
            //2.进行客户端身份的识别与鉴权
            std::string sid = req.session_id();
            auto uid = _redis_session->uid(sid);
            if(!uid)
            {
                LOG_ERROR("获取登录会话:{}关联的用户ID失败\n",sid);
                return err_handler("获取登录会话关联的用户ID失败");
            }
            req.set_user_id(*uid);
            //3.将请求转发到对应的子服务进行处理
            auto channel = _mm_channels->choose(_user_service_name);
            if(!channel)
            {
                LOG_ERROR("{}:未找到可提供获取设置签名的用户子服务节点\n",req.request_id());
                return err_handler("未找到可提供获取设置签名的用户子服务节点");
            }
            zzy_mims::UserService_Stub stub(channel.get());
            brpc::Controller cntl;
            stub.SetUserDescription(&cntl,&req,&rsp,nullptr);
            if(cntl.Failed())
            {
                LOG_ERROR("{}:用户子服务:获取设置签名调用失败\n",req.request_id());
                return err_handler("用户子服务:获取设置签名调用失败");
            }
            //执行错误也是一种正确的响应
            // if(!rsp.success())
            // {
            //     LOG_ERROR("{}:用户子服务:获取设置签名处理失败\n",req.request_id());
            //     return err_handler("用户子服务:获取设置签名处理失败");
            // }
            //4.得到正确的对应的子服务的响应后，将响应内容进行序列化作为http响应正文
            response.set_content(rsp.SerializeAsString(),"application/x-protobuf");
        }
        void SetUserPhoneNumber(const httplib::Request &request, httplib::Response &response) 
        {
            //1.取出http正文，将正文反序列化
            SetUserPhoneNumberReq req;
            SetUserPhoneNumberRsp rsp;
            auto err_handler = [&req,&rsp,&response](const std::string& errmsg)
            {
                rsp.set_success(false);
                rsp.set_errmsg(errmsg);
                response.set_content(rsp.SerializeAsString(),"application/x-protobuf");
                return;
            };
            bool ret = req.ParseFromString(request.body);
            if(!ret)
            {
                LOG_ERROR("获取设置电话请求反序列化失败\n");
                return err_handler("获取设置电话请求反序列化失败");
            }
            //2.进行客户端身份的识别与鉴权
            std::string sid = req.session_id();
            auto uid = _redis_session->uid(sid);
            if(!uid)
            {
                LOG_ERROR("获取登录会话:{}关联的用户ID失败\n",sid);
                return err_handler("获取登录会话关联的用户ID失败");
            }
            req.set_user_id(*uid);
            //3.将请求转发到对应的子服务进行处理
            auto channel = _mm_channels->choose(_user_service_name);
            if(!channel)
            {
                LOG_ERROR("{}:未找到可提供获取设置电话的用户子服务节点\n",req.request_id());
                return err_handler("未找到可提供获取设置电话的用户子服务节点");
            }
            zzy_mims::UserService_Stub stub(channel.get());
            brpc::Controller cntl;
            stub.SetUserPhoneNumber(&cntl,&req,&rsp,nullptr);
            if(cntl.Failed())
            {
                LOG_ERROR("{}:用户子服务:获取设置电话调用失败\n",req.request_id());
                return err_handler("用户子服务:获取设置电话调用失败");
            }
            //执行错误也是一种正确的响应
            // if(!rsp.success())
            // {
            //     LOG_ERROR("{}:用户子服务:获取设置电话处理失败\n",req.request_id());
            //     return err_handler("用户子服务:获取设置电话处理失败");
            // }
            //4.得到正确的对应的子服务的响应后，将响应内容进行序列化作为http响应正文
            response.set_content(rsp.SerializeAsString(),"application/x-protobuf");

        }
        void GetFriendList(const httplib::Request &request, httplib::Response &response)
        {
            //1.取出http正文，将正文反序列化
            GetFriendListReq req;
            GetFriendListRsp rsp;
            auto err_handler = [&req,&rsp,&response](const std::string& errmsg)
            {
                rsp.set_success(false);
                rsp.set_errmsg(errmsg);
                response.set_content(rsp.SerializeAsString(),"application/x-protobuf");
                return;
            };
            bool ret = req.ParseFromString(request.body);
            if(!ret)
            {
                LOG_ERROR("获取好友列表请求反序列化失败\n");
                return err_handler("获取好友列表请求反序列化失败");
            }
            //2.进行客户端身份的识别与鉴权
            std::string sid = req.session_id();
            auto uid = _redis_session->uid(sid);
            if(!uid)
            {
                LOG_ERROR("获取登录会话:{}关联的用户ID失败\n",sid);
                return err_handler("获取登录会话关联的用户ID失败");
            }
            req.set_user_id(*uid);
            //3.将请求转发到对应的子服务进行处理
            auto channel = _mm_channels->choose(_friend_service_name);
            if(!channel)
            {
                LOG_ERROR("{}:未找到可提供获取好友列表的好友子服务节点\n",req.request_id());
                return err_handler("未找到可提供获取好友列表的好友子服务节点");
            }
            zzy_mims::FriendService_Stub stub(channel.get());
            brpc::Controller cntl;
            stub.GetFriendList(&cntl,&req,&rsp,nullptr);
            if(cntl.Failed())
            {
                LOG_ERROR("{}:好友子服务:获取好友列表调用失败\n",req.request_id());
                return err_handler("好友子服务:获取好友列表调用失败");
            }
            //执行错误也是一种正确的响应
            // if(!rsp.success())
            // {
            //     LOG_ERROR("{}:好友子服务:获取好友列表处理失败\n",req.request_id());
            //     return err_handler("好友子服务:获取好友列表处理失败");
            // }
            //4.得到正确的对应的子服务的响应后，将响应内容进行序列化作为http响应正文
            response.set_content(rsp.SerializeAsString(),"application/x-protobuf");

        }
        std::shared_ptr<GetUserInfoRsp> _GetUserInfo(const std::string &rid, const std::string &uid)
        {
            GetUserInfoReq req;
            std::shared_ptr<GetUserInfoRsp> rsp = std::make_shared<GetUserInfoRsp>();
            req.set_request_id(rid);
            req.set_user_id(uid);

            auto channel = _mm_channels->choose(_user_service_name);
            if(!channel)
            {
                LOG_ERROR("{}:未找到可提供获取用户信息的用户子服务节点\n",rid);
                return std::make_shared<GetUserInfoRsp>();
            }
            zzy_mims::UserService_Stub stub(channel.get());
            brpc::Controller cntl;
            stub.GetUserInfo(&cntl,&req,rsp.get(),nullptr);
            if(cntl.Failed())
            {
                LOG_ERROR("{}:用户子服务:获取用户信息调用失败\n",rid);
                return std::make_shared<GetUserInfoRsp>();
            }
            //执行错误也是一种正确的响应
            // if(!rsp.success())
            // {
            //     LOG_ERROR("{}:用户子服务:获取用户信息处理失败\n",rid);
            //     return std::make_shared<GetUserInfoRsp>();
            // }
            return rsp;
        }
        void FriendAdd(const httplib::Request &request, httplib::Response &response)
        {
            //1.取出http正文，将正文反序列化
            FriendAddReq req;
            FriendAddRsp rsp;
            auto err_handler = [&req,&rsp,&response](const std::string& errmsg)
            {
                rsp.set_success(false);
                rsp.set_errmsg(errmsg);
                response.set_content(rsp.SerializeAsString(),"application/x-protobuf");
                return;
            };
            bool ret = req.ParseFromString(request.body);
            if(!ret)
            {
                LOG_ERROR("申请好友请求反序列化失败\n");
                return err_handler("申请好友请求反序列化失败");
            }
            //2.进行客户端身份的识别与鉴权
            std::string sid = req.session_id();
            auto uid = _redis_session->uid(sid);
            if(!uid)
            {
                LOG_ERROR("获取登录会话:{}关联的用户ID失败\n",sid);
                return err_handler("获取登录会话关联的用户ID失败");
            }
            req.set_user_id(*uid);
            //3.将请求转发到对应的子服务进行处理
            auto channel = _mm_channels->choose(_friend_service_name);
            if(!channel)
            {
                LOG_ERROR("{}:未找到可提供申请好友的好友子服务节点\n",req.request_id());
                return err_handler("未找到可提供申请好友列表的好友子服务节点");
            }
            zzy_mims::FriendService_Stub stub(channel.get());
            brpc::Controller cntl;
            stub.FriendAdd(&cntl,&req,&rsp,nullptr);
            if(cntl.Failed())
            {
                LOG_ERROR("{}:好友子服务:申请好友调用失败\n",req.request_id());
                return err_handler("好友子服务:申请好友调用失败");
            }
            //4.若业务处理成功且获取被申请方长连接成功，则向被申请方进行好友事件的通知
            auto conn = _conn->connection(req.respondent_id());
            if(rsp.success()&&conn)
            {
                LOG_DEBUG("找到被申请人{}的长连接，对其进行好友申请通知",req.respondent_id());
                auto rsp_user = _GetUserInfo(req.request_id(),*uid);
                if(rsp_user)
                {
                    LOG_ERROR("获取当前客户端:{}用户信息失败",req.respondent_id());
                    return err_handler("获取当前客户端用户信息失败");
                }
                NotifyMessage notify;
                notify.set_notify_type(NotifyType::FRIEND_ADD_APPLY_NOTIFY);
                notify.mutable_friend_add_apply()->mutable_user_info()->CopyFrom(rsp_user->user_info());
                conn->send(notify.SerializeAsString(),websocketpp::frame::opcode::value::binary);
            }
            //5.得到正确的对应的子服务的响应后，将响应内容进行序列化作为http响应正文
            response.set_content(rsp.SerializeAsString(),"application/x-protobuf");

        }
        void FriendAddProcess(const httplib::Request &request, httplib::Response &response)
        {
            //1.取出http正文，将正文反序列化
            FriendAddProcessReq req;
            FriendAddProcessRsp rsp;
            auto err_handler = [&req,&rsp,&response](const std::string& errmsg)
            {
                rsp.set_success(false);
                rsp.set_errmsg(errmsg);
                response.set_content(rsp.SerializeAsString(),"application/x-protobuf");
                return;
            };
            bool ret = req.ParseFromString(request.body);
            if(!ret)
            {
                LOG_ERROR("好友申请处理请求反序列化失败\n");
                return err_handler("好友申请处理请求反序列化失败");
            }
            //2.进行客户端身份的识别与鉴权
            std::string sid = req.session_id();
            auto uid = _redis_session->uid(sid);
            if(!uid)
            {
                LOG_ERROR("获取登录会话:{}关联的用户ID失败\n",sid);
                return err_handler("获取登录会话关联的用户ID失败");
            }
            req.set_user_id(*uid);
            //3.将请求转发到对应的子服务进行处理
            auto channel = _mm_channels->choose(_friend_service_name);
            if(!channel)
            {
                LOG_ERROR("{}:未找到可提供好友申请处理的好友子服务节点\n",req.request_id());
                return err_handler("未找到可提供好友申请处理列表的好友子服务节点");
            }
            zzy_mims::FriendService_Stub stub(channel.get());
            brpc::Controller cntl;
            stub.FriendAddProcess(&cntl,&req,&rsp,nullptr);
            if(cntl.Failed())
            {
                LOG_ERROR("{}:好友子服务:好友申请处理调用失败\n",req.request_id());
                return err_handler("好友子服务:好友申请处理调用失败");
            }
            //4.若业务处理成功,且能够获取申请人和被申请人的用户信息
                //1.若获取申请人长连接成功，则对申请人进行申请结果通知
                //2.若申请的结果是同意，则需要创建两人的会话，对申请人和被申请人进行会话的通知
            if(rsp.success())
            {
                auto rsp_process_user = _GetUserInfo(req.request_id(),*uid);
                if(!rsp_process_user)
                {
                    LOG_ERROR("{}:获取处理好友申请请求用户信息失败\n",req.request_id());
                    return err_handler("获取处理好友申请请求用户信息失败");
                }
                auto rsp_apply_user = _GetUserInfo(req.request_id(),req.apply_user_id());
                if(!rsp_apply_user)
                {
                    LOG_ERROR("{}:获取好友申请者用户信息失败\n",req.request_id());
                    return err_handler("获取好友申请者用户信息失败");
                }
                auto apply_conn = _conn->connection(req.apply_user_id());
                if(apply_conn) LOG_DEBUG("获取申请人:{}长连接成功\n",req.apply_user_id());
                else LOG_DEBUG("获取申请人:{}长连接失败\n",req.apply_user_id());
                auto process_conn = _conn->connection(*uid);
                if(apply_conn) LOG_DEBUG("获取处理好友申请请求用户:{}长连接成功\n",*uid);
                else LOG_DEBUG("获取处理好友申请请求用户:{}长连接失败\n",*uid);

                if(apply_conn)
                {
                    LOG_DEBUG("对申请人进行申请处理结果通知\n");
                    NotifyMessage notify;
                    notify.set_notify_type(NotifyType::FRIEND_ADD_PROCESS_NOTIFY);
                    notify.mutable_friend_process_result()->set_agree(req.agree());
                    notify.mutable_friend_process_result()->mutable_user_info()->CopyFrom(rsp_process_user->user_info());
                    apply_conn->send(notify.SerializeAsString(),websocketpp::frame::opcode::value::binary);
                    LOG_DEBUG("对申请人进行申请处理结果通知完成\n");
                }
                if(req.agree())
                {
                    if(apply_conn)
                    {
                        LOG_DEBUG("对申请人进行会话创建通知\n");
                        NotifyMessage notify;
                        notify.set_notify_type(NotifyType::CHAT_SESSION_CREATE_NOTIFY);
                        auto notify_cs_info = notify.mutable_new_chat_session_info()->mutable_chat_session_info();
                        notify_cs_info->set_single_chat_friend_id(*uid);
                        notify_cs_info->set_chat_session_id(rsp.new_session_id());
                        notify_cs_info->set_chat_session_name(rsp_process_user->user_info().nickname());
                        notify_cs_info->set_avatar(rsp_process_user->user_info().avatar());
                        apply_conn->send(notify.SerializeAsString(),websocketpp::frame::opcode::value::binary);
                        LOG_DEBUG("对申请人进行会话创建通知完成\n");
                    }
                    if(process_conn)
                    {
                        LOG_DEBUG("对申请执行人进行会话创建通知\n");
                        NotifyMessage notify;
                        notify.set_notify_type(NotifyType::CHAT_SESSION_CREATE_NOTIFY);
                        auto notify_cs_info = notify.mutable_new_chat_session_info()->mutable_chat_session_info();
                        notify_cs_info->set_single_chat_friend_id(req.apply_user_id());
                        notify_cs_info->set_chat_session_id(rsp.new_session_id());
                        notify_cs_info->set_chat_session_name(rsp_apply_user->user_info().nickname());
                        notify_cs_info->set_avatar(rsp_apply_user->user_info().avatar());
                        process_conn->send(notify.SerializeAsString(),websocketpp::frame::opcode::value::binary);
                        LOG_DEBUG("对申请执行人进行会话创建通知完成\n");
                    }
                }
                
            }
            //5.得到正确的对应的子服务的响应后，将响应内容进行序列化作为http响应正文
            response.set_content(rsp.SerializeAsString(),"application/x-protobuf");

        }
        void FriendRemove(const httplib::Request &request, httplib::Response &response) 
        {
            
            //1.取出http正文，将正文反序列化
            FriendRemoveReq req;
            FriendRemoveRsp rsp;
            auto err_handler = [&req,&rsp,&response](const std::string& errmsg)
            {
                rsp.set_success(false);
                rsp.set_errmsg(errmsg);
                response.set_content(rsp.SerializeAsString(),"application/x-protobuf");
                return;
            };
            bool ret = req.ParseFromString(request.body);
            if(!ret)
            {
                LOG_ERROR("好友删除请求反序列化失败\n");
                return err_handler("好友删除请求反序列化失败");
            }
            //2.进行客户端身份的识别与鉴权
            std::string sid = req.session_id();
            auto uid = _redis_session->uid(sid);
            if(!uid)
            {
                LOG_ERROR("获取登录会话:{}关联的用户ID失败\n",sid);
                return err_handler("获取登录会话关联的用户ID失败");
            }
            req.set_user_id(*uid);
            //3.将请求转发到对应的子服务进行处理
            auto channel = _mm_channels->choose(_friend_service_name);
            if(!channel)
            {
                LOG_ERROR("{}:未找到可提供好友删除的好友子服务节点\n",req.request_id());
                return err_handler("未找到可提供好友删除列表的好友子服务节点");
            }
            zzy_mims::FriendService_Stub stub(channel.get());
            brpc::Controller cntl;
            stub.FriendRemove(&cntl,&req,&rsp,nullptr);
            if(cntl.Failed())
            {
                LOG_ERROR("{}:好友子服务:好友删除调用失败\n",req.request_id());
                return err_handler("好友子服务:好友删除调用失败");
            }
            //4.若业务处理成功且获取长连接成功，向被删除方进行删除好友通知
            auto conn = _conn->connection(req.peer_id());
            if(rsp.success()&&conn)
            {
                LOG_DEBUG("找到被删除人{}的长连接，对其进行好友删除通知",req.peer_id());
                NotifyMessage notify;
                notify.set_notify_type(NotifyType::FRIEND_REMOVE_NOTIFY);
                notify.mutable_friend_remove()->set_user_id(*uid);
                conn->send(notify.SerializeAsString(),websocketpp::frame::opcode::value::binary);
            } 
            //5.得到正确的对应的子服务的响应后，将响应内容进行序列化作为http响应正文 
            response.set_content(rsp.SerializeAsString(),"application/x-protobuf");
        }
        void FriendSearch(const httplib::Request &request, httplib::Response &response) 
        {
            //1.取出http正文，将正文反序列化
            FriendSearchReq req;
            FriendSearchRsp rsp;
            auto err_handler = [&req,&rsp,&response](const std::string& errmsg)
            {
                rsp.set_success(false);
                rsp.set_errmsg(errmsg);
                response.set_content(rsp.SerializeAsString(),"application/x-protobuf");
                return;
            };
            bool ret = req.ParseFromString(request.body);
            if(!ret)
            {
                LOG_ERROR("好友搜索请求反序列化失败\n");
                return err_handler("好友搜索请求反序列化失败");
            }
            //2.进行客户端身份的识别与鉴权
            std::string sid = req.session_id();
            auto uid = _redis_session->uid(sid);
            if(!uid)
            {
                LOG_ERROR("获取登录会话:{}关联的用户ID失败\n",sid);
                return err_handler("获取登录会话关联的用户ID失败");
            }
            req.set_user_id(*uid);
            //3.将请求转发到对应的子服务进行处理
            auto channel = _mm_channels->choose(_friend_service_name);
            if(!channel)
            {
                LOG_ERROR("{}:未找到可提供好友搜索的好友子服务节点\n",req.request_id());
                return err_handler("未找到可提供好友搜索列表的好友子服务节点");
            }
            zzy_mims::FriendService_Stub stub(channel.get());
            brpc::Controller cntl;
            stub.FriendSearch(&cntl,&req,&rsp,nullptr);
            if(cntl.Failed())
            {
                LOG_ERROR("{}:好友子服务:好友搜索调用失败\n",req.request_id());
                return err_handler("好友子服务:好友搜索调用失败");
            }
            //4. 得到正确的对应的子服务的响应后，将响应内容进行序列化作为http响应正文
            response.set_content(rsp.SerializeAsString(),"application/x-protobuf");
        }
        void GetPendingFriendEventList(const httplib::Request &request, httplib::Response &response)
        {
             //1.取出http正文，将正文反序列化
             GetPendingFriendEventListReq req;
             GetPendingFriendEventListRsp rsp;
             auto err_handler = [&req,&rsp,&response](const std::string& errmsg)
             {
                 rsp.set_success(false);
                 rsp.set_errmsg(errmsg);
                 response.set_content(rsp.SerializeAsString(),"application/x-protobuf");
                 return;
             };
             bool ret = req.ParseFromString(request.body);
             if(!ret)
             {
                 LOG_ERROR("获取待处理好友申请请求反序列化失败\n");
                 return err_handler("获取待处理好友申请请求反序列化失败");
             }
             //2.进行客户端身份的识别与鉴权
             std::string sid = req.session_id();
             auto uid = _redis_session->uid(sid);
             if(!uid)
             {
                 LOG_ERROR("获取登录会话:{}关联的用户ID失败\n",sid);
                 return err_handler("获取登录会话关联的用户ID失败");
             }
             req.set_user_id(*uid);
             //3.将请求转发到对应的子服务进行处理
             auto channel = _mm_channels->choose(_friend_service_name);
             if(!channel)
             {
                 LOG_ERROR("{}:未找到可提供获取待处理好友申请的好友子服务节点\n",req.request_id());
                 return err_handler("未找到可提供获取待处理好友申请列表的好友子服务节点");
             }
             zzy_mims::FriendService_Stub stub(channel.get());
             brpc::Controller cntl;
             stub.GetPendingFriendEventList(&cntl,&req,&rsp,nullptr);
             if(cntl.Failed())
             {
                 LOG_ERROR("{}:好友子服务:获取待处理好友申请调用失败\n",req.request_id());
                 return err_handler("好友子服务:获取待处理好友申请调用失败");
             }
             //4. 得到正确的对应的子服务的响应后，将响应内容进行序列化作为http响应正文
             response.set_content(rsp.SerializeAsString(),"application/x-protobuf");

        }
        void GetChatSessionList(const httplib::Request &request, httplib::Response &response)
        {
            //1.取出http正文，将正文反序列化
            GetChatSessionListReq req;
            GetChatSessionListRsp rsp;
            auto err_handler = [&req,&rsp,&response](const std::string& errmsg)
            {
                rsp.set_success(false);
                rsp.set_errmsg(errmsg);
                response.set_content(rsp.SerializeAsString(),"application/x-protobuf");
                return;
            };
            bool ret = req.ParseFromString(request.body);
            if(!ret)
            {
                LOG_ERROR("获取聊天会话列表请求反序列化失败\n");
                return err_handler("获取聊天会话列表请求反序列化失败");
            }
            //2.进行客户端身份的识别与鉴权
            std::string sid = req.session_id();
            auto uid = _redis_session->uid(sid);
            if(!uid)
            {
                LOG_ERROR("获取登录会话:{}关联的用户ID失败\n",sid);
                return err_handler("获取登录会话关联的用户ID失败");
            }
            req.set_user_id(*uid);
            //3.将请求转发到对应的子服务进行处理
            auto channel = _mm_channels->choose(_friend_service_name);
            if(!channel)
            {
                LOG_ERROR("{}:未找到可提供获取聊天会话列表申请的好友子服务节点\n",req.request_id());
                return err_handler("未找到可提供获取聊天会话列表申请列表的好友子服务节点");
            }
            zzy_mims::FriendService_Stub stub(channel.get());
            brpc::Controller cntl;
            stub.GetChatSessionList(&cntl,&req,&rsp,nullptr);
            if(cntl.Failed())
            {
                LOG_ERROR("{}:好友子服务:获取聊天会话列表申请调用失败\n",req.request_id());
                return err_handler("好友子服务:获取聊天会话列表申请调用失败");
            }
            //4. 得到正确的对应的子服务的响应后，将响应内容进行序列化作为http响应正文
            response.set_content(rsp.SerializeAsString(),"application/x-protobuf");

        }
        void GetChatSessionMember(const httplib::Request &request, httplib::Response &response)
        {
            //1.取出http正文，将正文反序列化
            GetChatSessionMemberReq req;
            GetChatSessionMemberRsp rsp;
            auto err_handler = [&req,&rsp,&response](const std::string& errmsg)
            {
                rsp.set_success(false);
                rsp.set_errmsg(errmsg);
                response.set_content(rsp.SerializeAsString(),"application/x-protobuf");
                return;
            };
            bool ret = req.ParseFromString(request.body);
            if(!ret)
            {
                LOG_ERROR("获取聊天会话成员列表请求反序列化失败\n");
                return err_handler("获取聊天会话成员列表请求反序列化失败");
            }
            //2.进行客户端身份的识别与鉴权
            std::string sid = req.session_id();
            auto uid = _redis_session->uid(sid);
            if(!uid)
            {
                LOG_ERROR("获取登录会话:{}关联的用户ID失败\n",sid);
                return err_handler("获取登录会话关联的用户ID失败");
            }
            req.set_user_id(*uid);
            //3.将请求转发到对应的子服务进行处理
            auto channel = _mm_channels->choose(_friend_service_name);
            if(!channel)
            {
                LOG_ERROR("{}:未找到可提供获取聊天会话成员列表申请的好友子服务节点\n",req.request_id());
                return err_handler("未找到可提供获取聊天会话成员列表申请列表的好友子服务节点");
            }
            zzy_mims::FriendService_Stub stub(channel.get());
            brpc::Controller cntl;
            stub.GetChatSessionMember(&cntl,&req,&rsp,nullptr);
            if(cntl.Failed())
            {
                LOG_ERROR("{}:好友子服务:获取聊天会话成员列表申请调用失败\n",req.request_id());
                return err_handler("好友子服务:获取聊天会话成员列表申请调用失败");
            }
            //4. 得到正确的对应的子服务的响应后，将响应内容进行序列化作为http响应正文
            response.set_content(rsp.SerializeAsString(),"application/x-protobuf");

        }
        void ChatSessionCreate(const httplib::Request &request, httplib::Response &response)
        {
             //1.取出http正文，将正文反序列化
             ChatSessionCreateReq req;
             ChatSessionCreateRsp rsp;
             auto err_handler = [&req,&rsp,&response](const std::string& errmsg)
             {
                 rsp.set_success(false);
                 rsp.set_errmsg(errmsg);
                 response.set_content(rsp.SerializeAsString(),"application/x-protobuf");
                 return;
             };
             bool ret = req.ParseFromString(request.body);
             if(!ret)
             {
                 LOG_ERROR("创建会话请求反序列化失败\n");
                 return err_handler("创建会话请求反序列化失败");
             }
             //2.进行客户端身份的识别与鉴权
             std::string sid = req.session_id();
             auto uid = _redis_session->uid(sid);
             if(!uid)
             {
                 LOG_ERROR("获取登录会话:{}关联的用户ID失败\n",sid);
                 return err_handler("获取登录会话关联的用户ID失败");
             }
             req.set_user_id(*uid);
             //3.将请求转发到对应的子服务进行处理
             auto channel = _mm_channels->choose(_friend_service_name);
             if(!channel)
             {
                 LOG_ERROR("{}:未找到可提供获创建会话的好友子服务节点\n",req.request_id());
                 return err_handler("未找到可提供创建会话的好友子服务节点");
             }
             zzy_mims::FriendService_Stub stub(channel.get());
             brpc::Controller cntl;
             stub.ChatSessionCreate(&cntl,&req,&rsp,nullptr);
             if(cntl.Failed())
             {
                 LOG_ERROR("{}:好友子服务:创建会话申请调用失败\n",req.request_id());
                 return err_handler("好友子服务:创建会话申请调用失败");
             }
             //4.若业务处理成功且获取长连接成功，向新创建的会话的成员通知
             if(rsp.success())
             {
                for(int i =0;i<req.member_id_list_size();i++)
                {
                    auto conn = _conn->connection(req.member_id_list(i));
                    if(conn)
                    {
                        LOG_DEBUG("找到群聊成员{}的长连接，对其进行会话创建通知\n",req.member_id_list(i));
                        NotifyMessage notify;
                        notify.set_notify_type(NotifyType::CHAT_SESSION_CREATE_NOTIFY);
                        notify.mutable_new_chat_session_info()->mutable_chat_session_info()->CopyFrom(rsp.chat_session_info());
                        conn->send(notify.SerializeAsString(),websocketpp::frame::opcode::value::binary);
                        LOG_DEBUG("对群聊成员{}进行会话创建通知完毕\n",req.member_id_list(i));
                    }
                }
             } 
             //5. 得到正确的对应的子服务的响应后，将响应内容进行序列化作为http响应正文
             response.set_content(rsp.SerializeAsString(),"application/x-protobuf");

        }
        void GetHistoryMsg(const httplib::Request &request, httplib::Response &response) 
        {
            //1.取出http正文，将正文反序列化
            GetHistoryMsgReq req;
            GetHistoryMsgRsp rsp;
            auto err_handler = [&req,&rsp,&response](const std::string& errmsg)
            {
                rsp.set_success(false);
                rsp.set_errmsg(errmsg);
                response.set_content(rsp.SerializeAsString(),"application/x-protobuf");
                return;
            };
            bool ret = req.ParseFromString(request.body);
            if(!ret)
            {
                LOG_ERROR("获取历史消息请求反序列化失败\n");
                return err_handler("获取历史消息请求反序列化失败");
            }
            //2.进行客户端身份的识别与鉴权
            std::string sid = req.session_id();
            auto uid = _redis_session->uid(sid);
            if(!uid)
            {
                LOG_ERROR("获取登录会话:{}关联的用户ID失败\n",sid);
                return err_handler("获取登录会话关联的用户ID失败");
            }
            req.set_user_id(*uid);
            //3.将请求转发到对应的子服务进行处理
            auto channel = _mm_channels->choose(_message_service_name);
            if(!channel)
            {
                LOG_ERROR("{}:未找到可提供获取历史消息申请的好友子服务节点\n",req.request_id());
                return err_handler("未找到可提供获取历史消息申请列表的好友子服务节点");
            }
            zzy_mims::MsgStorageService_Stub stub(channel.get());
            brpc::Controller cntl;
            stub.GetHistoryMsg(&cntl,&req,&rsp,nullptr);
            if(cntl.Failed())
            {
                LOG_ERROR("{}:消息存储子服务:获取历史消息申请调用失败\n",req.request_id());
                return err_handler("消息存储子服务:获取历史消息申请调用失败");
            }
            //4. 得到正确的对应的子服务的响应后，将响应内容进行序列化作为http响应正文
            response.set_content(rsp.SerializeAsString(),"application/x-protobuf");

        }
        void GetRecentMsg(const httplib::Request &request, httplib::Response &response)
        {
            //1.取出http正文，将正文反序列化
            GetRecentMsgReq req;
            GetRecentMsgRsp rsp;
            auto err_handler = [&req,&rsp,&response](const std::string& errmsg)
            {
                rsp.set_success(false);
                rsp.set_errmsg(errmsg);
                response.set_content(rsp.SerializeAsString(),"application/x-protobuf");
                return;
            };
            bool ret = req.ParseFromString(request.body);
            if(!ret)
            {
                LOG_ERROR("获取最近消息请求反序列化失败\n");
                return err_handler("获取最近消息请求反序列化失败");
            }
            //2.进行客户端身份的识别与鉴权
            std::string sid = req.session_id();
            auto uid = _redis_session->uid(sid);
            if(!uid)
            {
                LOG_ERROR("获取登录会话:{}关联的用户ID失败\n",sid);
                return err_handler("获取登录会话关联的用户ID失败");
            }
            req.set_user_id(*uid);
            //3.将请求转发到对应的子服务进行处理
            auto channel = _mm_channels->choose(_message_service_name);
            if(!channel)
            {
                LOG_ERROR("{}:未找到可提供获取最近消息申请的好友子服务节点\n",req.request_id());
                return err_handler("未找到可提供获取最近消息申请列表的好友子服务节点");
            }
            zzy_mims::MsgStorageService_Stub stub(channel.get());
            brpc::Controller cntl;
            stub.GetRecentMsg(&cntl,&req,&rsp,nullptr);
            if(cntl.Failed())
            {
                LOG_ERROR("{}:消息存储子服务:获取最近消息申请调用失败\n",req.request_id());
                return err_handler("消息存储子服务:获取最近消息申请调用失败");
            }
            //4. 得到正确的对应的子服务的响应后，将响应内容进行序列化作为http响应正文
            response.set_content(rsp.SerializeAsString(),"application/x-protobuf");

        }
        void MsgSearch(const httplib::Request &request, httplib::Response &response)
        {
            //1.取出http正文，将正文反序列化
            MsgSearchReq req;
            MsgSearchRsp rsp;
            auto err_handler = [&req,&rsp,&response](const std::string& errmsg)
            {
                rsp.set_success(false);
                rsp.set_errmsg(errmsg);
                response.set_content(rsp.SerializeAsString(),"application/x-protobuf");
                return;
            };
            bool ret = req.ParseFromString(request.body);
            if(!ret)
            {
                LOG_ERROR("消息搜索请求反序列化失败\n");
                return err_handler("消息搜索请求反序列化失败");
            }
            //2.进行客户端身份的识别与鉴权
            std::string sid = req.session_id();
            auto uid = _redis_session->uid(sid);
            if(!uid)
            {
                LOG_ERROR("获取登录会话:{}关联的用户ID失败\n",sid);
                return err_handler("获取登录会话关联的用户ID失败");
            }
            req.set_user_id(*uid);
            //3.将请求转发到对应的子服务进行处理
            auto channel = _mm_channels->choose(_message_service_name);
            if(!channel)
            {
                LOG_ERROR("{}:未找到可提供消息搜索申请的好友子服务节点\n",req.request_id());
                return err_handler("未找到可提供消息搜索申请列表的好友子服务节点");
            }
            zzy_mims::MsgStorageService_Stub stub(channel.get());
            brpc::Controller cntl;
            stub.MsgSearch(&cntl,&req,&rsp,nullptr);
            if(cntl.Failed())
            {
                LOG_ERROR("{}:消息存储子服务:消息搜索申请调用失败\n",req.request_id());
                return err_handler("消息存储子服务:消息搜索申请调用失败");
            }
            //4. 得到正确的对应的子服务的响应后，将响应内容进行序列化作为http响应正文
            response.set_content(rsp.SerializeAsString(),"application/x-protobuf");
        }
        void GetSingleFile(const httplib::Request &request, httplib::Response &response)
        {
            //1.取出http正文，将正文反序列化
            GetSingleFileReq req;
            GetSingleFileRsp rsp;
            auto err_handler = [&req,&rsp,&response](const std::string& errmsg)
            {
                rsp.set_success(false);
                rsp.set_errmsg(errmsg);
                response.set_content(rsp.SerializeAsString(),"application/x-protobuf");
                return;
            };
            bool ret = req.ParseFromString(request.body);
            if(!ret)
            {
                LOG_ERROR("单个文件下载请求反序列化失败\n");
                return err_handler("单个文件下载请求反序列化失败");
            }
            //2.进行客户端身份的识别与鉴权
            std::string sid = req.session_id();
            auto uid = _redis_session->uid(sid);
            if(!uid)
            {
                LOG_ERROR("获取登录会话:{}关联的用户ID失败\n",sid);
                return err_handler("获取登录会话关联的用户ID失败");
            }
            req.set_user_id(*uid);
            //3.将请求转发到对应的子服务进行处理
            auto channel = _mm_channels->choose(_file_service_name);
            if(!channel)
            {
                LOG_ERROR("{}:未找到可提供单个文件下载申请的好友子服务节点\n",req.request_id());
                return err_handler("未找到可提供单个文件下载申请列表的好友子服务节点");
            }
            zzy_mims::FileService_Stub stub(channel.get());
            brpc::Controller cntl;
            stub.GetSingleFile(&cntl,&req,&rsp,nullptr);
            if(cntl.Failed())
            {
                LOG_ERROR("{}:文件子服务:单个文件下载申请调用失败\n",req.request_id());
                return err_handler("文件子服务:单个文件下载申请调用失败");
            }
            //4. 得到正确的对应的子服务的响应后，将响应内容进行序列化作为http响应正文
            response.set_content(rsp.SerializeAsString(),"application/x-protobuf");

        }
        void GetMultiFile(const httplib::Request &request, httplib::Response &response)
        {
            //1.取出http正文，将正文反序列化
            GetMultiFileReq req;
            GetMultiFileRsp rsp;
            auto err_handler = [&req,&rsp,&response](const std::string& errmsg)
            {
                rsp.set_success(false);
                rsp.set_errmsg(errmsg);
                response.set_content(rsp.SerializeAsString(),"application/x-protobuf");
                return;
            };
            bool ret = req.ParseFromString(request.body);
            if(!ret)
            {
                LOG_ERROR("多个文件下载请求反序列化失败\n");
                return err_handler("多个文件下载请求反序列化失败");
            }
            //2.进行客户端身份的识别与鉴权
            std::string sid = req.session_id();
            auto uid = _redis_session->uid(sid);
            if(!uid)
            {
                LOG_ERROR("获取登录会话:{}关联的用户ID失败\n",sid);
                return err_handler("获取登录会话关联的用户ID失败");
            }
            req.set_user_id(*uid);
            //3.将请求转发到对应的子服务进行处理
            auto channel = _mm_channels->choose(_file_service_name);
            if(!channel)
            {
                LOG_ERROR("{}:未找到可提供多个文件下载申请的好友子服务节点\n",req.request_id());
                return err_handler("未找到可提供多个文件下载申请列表的好友子服务节点");
            }
            zzy_mims::FileService_Stub stub(channel.get());
            brpc::Controller cntl;
            stub.GetMultiFile(&cntl,&req,&rsp,nullptr);
            if(cntl.Failed())
            {
                LOG_ERROR("{}:文件子服务:多个文件下载申请调用失败\n",req.request_id());
                return err_handler("文件子服务:多个文件下载申请调用失败");
            }
            //4. 得到正确的对应的子服务的响应后，将响应内容进行序列化作为http响应正文
            response.set_content(rsp.SerializeAsString(),"application/x-protobuf");

        }
        void PutSingleFile(const httplib::Request &request, httplib::Response &response) 
        {
            //1.取出http正文，将正文反序列化
            PutSingleFileReq req;
            PutSingleFileRsp rsp;
            auto err_handler = [&req,&rsp,&response](const std::string& errmsg)
            {
                rsp.set_success(false);
                rsp.set_errmsg(errmsg);
                response.set_content(rsp.SerializeAsString(),"application/x-protobuf");
                return;
            };
            bool ret = req.ParseFromString(request.body);
            if(!ret)
            {
                LOG_ERROR("单个文件上传请求反序列化失败\n");
                return err_handler("单个文件上传请求反序列化失败");
            }
            //2.进行客户端身份的识别与鉴权
            std::string sid = req.session_id();
            auto uid = _redis_session->uid(sid);
            if(!uid)
            {
                LOG_ERROR("获取登录会话:{}关联的用户ID失败\n",sid);
                return err_handler("获取登录会话关联的用户ID失败");
            }
            req.set_user_id(*uid);
            //3.将请求转发到对应的子服务进行处理
            auto channel = _mm_channels->choose(_file_service_name);
            if(!channel)
            {
                LOG_ERROR("{}:未找到可提供单个文件上传申请的好友子服务节点\n",req.request_id());
                return err_handler("未找到可提供单个文件上传申请列表的好友子服务节点");
            }
            zzy_mims::FileService_Stub stub(channel.get());
            brpc::Controller cntl;
            stub.PutSingleFile(&cntl,&req,&rsp,nullptr);
            if(cntl.Failed())
            {
                LOG_ERROR("{}:文件子服务:单个文件上传申请调用失败\n",req.request_id());
                return err_handler("文件子服务:单个文件上传申请调用失败");
            }
            //4. 得到正确的对应的子服务的响应后，将响应内容进行序列化作为http响应正文
            response.set_content(rsp.SerializeAsString(),"application/x-protobuf");
        }
        void PutMultiFile(const httplib::Request &request, httplib::Response &response) 
        {
            //1.取出http正文，将正文反序列化
            PutMultiFileReq req;
            PutMultiFileRsp rsp;
            auto err_handler = [&req,&rsp,&response](const std::string& errmsg)
            {
                rsp.set_success(false);
                rsp.set_errmsg(errmsg);
                response.set_content(rsp.SerializeAsString(),"application/x-protobuf");
                return;
            };
            bool ret = req.ParseFromString(request.body);
            if(!ret)
            {
                LOG_ERROR("多个文件上传请求反序列化失败\n");
                return err_handler("多个文件上传请求反序列化失败");
            }
            //2.进行客户端身份的识别与鉴权
            std::string sid = req.session_id();
            auto uid = _redis_session->uid(sid);
            if(!uid)
            {
                LOG_ERROR("获取登录会话:{}关联的用户ID失败\n",sid);
                return err_handler("获取登录会话关联的用户ID失败");
            }
            req.set_user_id(*uid);
            //3.将请求转发到对应的子服务进行处理
            auto channel = _mm_channels->choose(_file_service_name);
            if(!channel)
            {
                LOG_ERROR("{}:未找到可提供多个文件上传申请的好友子服务节点\n",req.request_id());
                return err_handler("未找到可提供多个文件上传申请列表的好友子服务节点");
            }
            zzy_mims::FileService_Stub stub(channel.get());
            brpc::Controller cntl;
            stub.PutMultiFile(&cntl,&req,&rsp,nullptr);
            if(cntl.Failed())
            {
                LOG_ERROR("{}:文件子服务:多个文件上传申请调用失败\n",req.request_id());
                return err_handler("文件子服务:多个文件上传申请调用失败");
            }
            //4. 得到正确的对应的子服务的响应后，将响应内容进行序列化作为http响应正文
            response.set_content(rsp.SerializeAsString(),"application/x-protobuf");

        }
        void SpeechRecognition(const httplib::Request &request, httplib::Response &response) 
        {
            //1.取出http正文，将正文反序列化
            SpeechRecognitionReq req;
            SpeechRecognitionRsp rsp;
            auto err_handler = [&req,&rsp,&response](const std::string& errmsg)
            {
                rsp.set_success(false);
                rsp.set_errmsg(errmsg);
                response.set_content(rsp.SerializeAsString(),"application/x-protobuf");
                return;
            };
            bool ret = req.ParseFromString(request.body);
            if(!ret)
            {
                LOG_ERROR("语音识别请求反序列化失败\n");
                return err_handler("语音识别请求反序列化失败");
            }
            //2.进行客户端身份的识别与鉴权
            std::string sid = req.session_id();
            auto uid = _redis_session->uid(sid);
            if(!uid)
            {
                LOG_ERROR("获取登录会话:{}关联的用户ID失败\n",sid);
                return err_handler("获取登录会话关联的用户ID失败");
            }
            req.set_user_id(*uid);
            //3.将请求转发到对应的子服务进行处理
            auto channel = _mm_channels->choose(_speech_service_name);
            if(!channel)
            {
                LOG_ERROR("{}:未找到可提供语音识别申请的好友子服务节点\n",req.request_id());
                return err_handler("未找到可提供语音识别申请列表的好友子服务节点");
            }
            zzy_mims::SpeechService_Stub stub(channel.get());
            brpc::Controller cntl;
            stub.SpeechRecognition(&cntl,&req,&rsp,nullptr);
            if(cntl.Failed())
            {
                LOG_ERROR("{}:语音子服务:语音识别申请调用失败\n",req.request_id());
                return err_handler("语音子服务:语音识别申请调用失败");
            }
            //4. 得到正确的对应的子服务的响应后，将响应内容进行序列化作为http响应正文
            response.set_content(rsp.SerializeAsString(),"application/x-protobuf");

        }
        void NewMessage(const httplib::Request &request, httplib::Response &response) 
        {
            //1.取出http正文，将正文反序列化
            NewMessageReq req;
            NewMessageRsp rsp;
            GetTransmitTargetRsp tar_rsp;
            auto err_handler = [&req,&rsp,&response](const std::string& errmsg)
            {
                rsp.set_success(false);
                rsp.set_errmsg(errmsg);
                response.set_content(rsp.SerializeAsString(),"application/x-protobuf");
                return;
            };
            bool ret = req.ParseFromString(request.body);
            if(!ret)
            {
                LOG_ERROR("新消息请求反序列化失败\n");
                return err_handler("新消息请求反序列化失败");
            }
            //2.进行客户端身份的识别与鉴权
            std::string sid = req.session_id();
            auto uid = _redis_session->uid(sid);
            if(!uid)
            {
                LOG_ERROR("获取登录会话:{}关联的用户ID失败\n",sid);
                return err_handler("获取登录会话关联的用户ID失败");
            }
            req.set_user_id(*uid);
            //3.将请求转发到对应的子服务进行处理
            auto channel = _mm_channels->choose(_transmit_service_name);
            if(!channel)
            {
                LOG_ERROR("{}:未找到可提供新消息的好友子服务节点\n",req.request_id());
                return err_handler("未找到可提供新消息的好友子服务节点");
            }
            zzy_mims::MsgTransmitService_Stub stub(channel.get());
            brpc::Controller cntl;
            stub.GetTransmitTarget(&cntl,&req,&tar_rsp,nullptr);
            if(cntl.Failed())
            {
                LOG_ERROR("{}:消息转发子服务:新消息调用失败\n",req.request_id());
                return err_handler("消息转发子服务:新消息调用失败");
            }
            //4.若业务处理成功且获取长连接成功，向消息接受方进行新消息通知
            if(rsp.success())
             {
                for(int i =0;i<tar_rsp.target_id_list_size();i++)
                {
                    //不通知自己
                    if(tar_rsp.target_id_list(i)==*uid)
                    continue;
                    auto conn = _conn->connection(tar_rsp.target_id_list(i));
                    if(conn)
                    {
                        LOG_DEBUG("找到群聊成员{}的长连接，对其进行新消息通知\n",tar_rsp.target_id_list(i));
                        NotifyMessage notify;
                        notify.set_notify_type(NotifyType::CHAT_MESSAGE_NOTIFY);
                        notify.mutable_new_message_info()->mutable_message_info()->CopyFrom(tar_rsp.message());
                        conn->send(notify.SerializeAsString(),websocketpp::frame::opcode::value::binary);
                        LOG_DEBUG("对群聊成员{}进行新消息通知完毕\n",tar_rsp.target_id_list(i));
                    }
                }
             } 
            //5.得到正确的对应的子服务的响应后，将响应内容进行序列化作为http响应正文
            rsp.set_request_id(tar_rsp.request_id()); 
            rsp.set_success(tar_rsp.success());
            rsp.set_errmsg(tar_rsp.errmsg());

            response.set_content(rsp.SerializeAsString(),"application/x-protobuf");
        }
    private:
        Session::ptr _redis_session;
        Status::ptr _redis_status;

        std::string _user_service_name;
        std::string _file_service_name;
        std::string _speech_service_name;
        std::string _message_service_name;
        std::string _transmit_service_name;
        std::string _friend_service_name;

        ServChanManager::ptr _mm_channels;
        Discovery::ptr _service_discoverer;

        Connection::ptr _conn;
        server_t _ws_server;
        httplib::Server _http_server;
        std::thread _http_thread;
        std::unordered_map<size_t,bool> _judge_alive;//防止同一个长连接进行多次保活调用
    };
    class GatewayServerBuilder
    {
    public:
        //GatewayServerBuilder(){};
        //~GatewayServerBuilder(){};

        void make_redis_object(const std::string& host,const int port,const int db,bool keep_alive)
        {
            _redis_client = RedisClientFactory::create(host,port,db,keep_alive);
        }
        void make_discover_object(const std::string& etcd_host,
        const std::string& base_service_name,const std::string& file_service_name,const std::string& user_service_name,
        const std::string& transmit_service_name,const std::string& friend_service_name,const std::string& message_service_name,
        const std::string& speech_service_name)
        {
            _file_service_name = file_service_name;
            _user_service_name = user_service_name;
            _transmit_service_name = transmit_service_name;
            _friend_service_name = friend_service_name;
            _message_service_name = message_service_name;
            _speech_service_name = speech_service_name;

            _mm_channels = std::make_shared<ServChanManager>();
            _mm_channels->Declared(file_service_name);
            _mm_channels->Declared(user_service_name);
            _mm_channels->Declared(transmit_service_name);
            _mm_channels->Declared(friend_service_name);
            _mm_channels->Declared(message_service_name);
            _mm_channels->Declared(speech_service_name);
            auto online = bind(&zzy_mims::ServChanManager::ServiceOnline,_mm_channels.get(),std::placeholders::_1,std::placeholders::_2);
            auto offline = bind(&zzy_mims::ServChanManager::ServiceOffline,_mm_channels.get(),std::placeholders::_1,std::placeholders::_2);
            _service_discoverer = std::make_shared<zzy_mims::Discovery>(etcd_host,base_service_name,online,offline);
        }
        void make_server_object(int websocket_port,int http_port)
        {
            _websocket_port= websocket_port;
            _http_port = http_port;
        }
    
        GatewayServer::ptr build()
        {
            if(!_redis_client)
            {
                LOG_ERROR("构造rpc服务时,还未初始化Redis客户端\n");
                abort();
            }
            if(!_mm_channels)
            {
                LOG_ERROR("未初始化信道管理模块\n");
                abort();
            }
            if(!_service_discoverer)
            {
                LOG_ERROR("未初始化服务发现模块\n");
                abort(); 
            }
            GatewayServer::ptr server = std::make_shared<GatewayServer>(_websocket_port,_http_port,_redis_client,
                _mm_channels,_service_discoverer,_user_service_name,_file_service_name,_speech_service_name,
                _message_service_name,_transmit_service_name,_friend_service_name);
            return server;
        }
    private:
    int _websocket_port;
    int _http_port;


    std::shared_ptr<sw::redis::Redis> _redis_client;

    std::string _user_service_name;
    std::string _file_service_name;
    std::string _speech_service_name;
    std::string _message_service_name;
    std::string _transmit_service_name;
    std::string _friend_service_name;

    ServChanManager::ptr _mm_channels;
    Discovery::ptr _service_discoverer;
        
    };
}
